package com.d3works.apps.stock.service;

import com.d3works.apps.base.db.*;
import com.d3works.apps.stock.db.*;
import com.d3works.exception.D3worksException;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public interface StockMoveService {

  /**
   * Generic method to create any stock move
   *
   * @param fromAddress
   * @param toAddress
   * @param company
   * @param clientPartner
   * @param fromStockLocation
   * @param toStockLocation
   * @param realDate
   * @param estimatedDate
   * @param note
   * @param shipmentMode
   * @param freightCarrierMode
   * @param carrierPartner
   * @param forwarderPartner
   * @param incoterm
   * @param typeSelect
   * @return
   * @throws D3worksException No Stock move sequence defined
   */
  public StockMove createStockMove(
      Address fromAddress,
      Address toAddress,
      Company company,
      Partner clientPartner,
      StockLocation fromStockLocation,
      StockLocation toStockLocation,
      LocalDate realDate,
      LocalDate estimatedDate,
      String note,
      ShipmentMode shipmentMode,
      FreightCarrierMode freightCarrierMode,
      Partner carrierPartner,
      Partner forwarderPartner,
      Incoterm incoterm,
      int typeSelect)
      throws D3worksException;

  /**
   * Generic method to create any stock move for internal stock move (without partner information)
   *
   * @param fromAddress
   * @param toAddress
   * @param company
   * @param fromStockLocation
   * @param toStockLocation
   * @param realDate
   * @param estimatedDate
   * @param note
   * @param typeSelect
   * @return
   * @throws D3worksException No Stock move sequence defined
   */
  public StockMove createStockMove(
      Address fromAddress,
      Address toAddress,
      Company company,
      StockLocation fromStockLocation,
      StockLocation toStockLocation,
      LocalDate realDate,
      LocalDate estimatedDate,
      String note,
      int typeSelect)
      throws D3worksException;

  /** To create an internal stock move with one product, mostly for mobile app (API AOS) * */
  StockMove createStockMoveMobility(
      StockLocation fromStockLocation,
      StockLocation toStockLocation,
      Company company,
      Product product,
      TrackingNumber trackNb,
      BigDecimal movedQty,
      Unit unit)
      throws D3worksException;

  public void validate(StockMove stockMove) throws D3worksException;

  public void goBackToDraft(StockMove stockMove) throws D3worksException;

  public void plan(StockMove stockMove) throws D3worksException;

  public String realize(StockMove stockMove) throws D3worksException;

  public String realize(StockMove stockMove, boolean check) throws D3worksException;

  public boolean mustBeSplit(List<StockMoveLine> stockMoveLineList);

  public Optional<StockMove> copyAndSplitStockMove(StockMove stockMove) throws D3worksException;

  public Optional<StockMove> copyAndSplitStockMove(
      StockMove stockMove, List<StockMoveLine> stockMoveLines) throws D3worksException;

  public Optional<StockMove> copyAndSplitStockMoveReverse(StockMove stockMove, boolean split)
      throws D3worksException;

  public Optional<StockMove> copyAndSplitStockMoveReverse(
      StockMove stockMove, List<StockMoveLine> stockMoveLines, boolean split)
      throws D3worksException;

  void cancel(StockMove stockMove) throws D3worksException;

  void cancel(StockMove stockMove, CancelReason cancelReason) throws D3worksException;

  @Transactional
  public boolean splitStockMoveLines(
      StockMove stockMove, List<StockMoveLine> stockMoveLines, BigDecimal splitQty);

  @Transactional
  public void copyQtyToRealQty(StockMove stockMove);

  @Transactional(rollbackOn = {Exception.class})
  public Optional<StockMove> generateReversion(StockMove stockMove) throws D3worksException;

  public StockMove splitInto2(
      StockMove originalStockMove, List<StockMoveLine> modifiedStockMoveLines)
      throws D3worksException;

  public List<Map<String, Object>> getStockPerDate(
      Long locationId, Long productId, LocalDate fromDate, LocalDate toDate);

  /**
   * Change conformity on each stock move line according to the stock move conformity.
   *
   * @param stockMove
   * @return
   */
  List<StockMoveLine> changeConformityStockMove(StockMove stockMove);

  /**
   * Change stock move conformity according to the conformity on each stock move line.
   *
   * @param stockMove
   * @return
   */
  Integer changeConformityStockMoveLine(StockMove stockMove);

  /**
   * Called from {@link com.d3works.apps.stock.web.StockMoveController#viewDirection}
   *
   * @param stockMove
   * @return the direction for the google map API
   */
  Map<String, Object> viewDirection(StockMove stockMove) throws D3worksException;

  /**
   * Print the given stock move.
   *
   * @param stockMove
   * @param lstSelectedMove
   * @param reportType true if we print a picking order
   * @return the link to the PDF file
   * @throws D3worksException
   */
  String printStockMove(StockMove stockMove, List<Integer> lstSelectedMove, String reportType)
      throws D3worksException;

  /**
   * Update fully spread over logistical forms flag on stock move.
   *
   * @param stockMove
   */
  void updateFullySpreadOverLogisticalFormsFlag(StockMove stockMove);

  void setAvailableStatus(StockMove stockMove);

  /**
   * Update editDate of one Outgoing Stock Move
   *
   * @param stockMove
   * @param userType
   */
  void setPickingStockMoveEditDate(StockMove stockMove, String userType);

  /**
   * Update editDate of a list of Outgoing Stock Move
   *
   * @param ids
   * @param userType
   */
  void setPickingStockMovesEditDate(List<Long> ids, String userType);

  /**
   * Update stocks using saved stock move line list and current stock move line list. Then we save
   * current stock move line list, replacing the saved list.
   *
   * @param stockMove
   */
  void updateStocks(StockMove stockMove) throws D3worksException;

  void updateProductNetMass(StockMove stockMove) throws D3worksException;

  /**
   * Update locations from a planned stock move, by copying stock move lines in the stock move then
   * updating locations.
   *
   * @param stockMove
   * @param fromStockLocation
   * @param toStockLocation
   * @param initialStatus the initial status of the stock move.
   * @throws D3worksException
   */
  void updateLocations(
      StockMove stockMove,
      StockLocation fromStockLocation,
      StockLocation toStockLocation,
      int initialStatus)
      throws D3worksException;
}
